//called by the LevGun (Weapon) class, this is the makeshift constructor
//for the LevManager class. it accepts the Weapon that did the shooting
//and the object it shot as parameters, and creates some shortcuts to
//various other properties from those two objects (for easier
//access/readability)

class LevManager extends Actor;

var bool pullOnceDepletionBool; //so it only takes away a chunk one tick

var EnyaraPlayerController MPC;
var EnyaraPawn P;
var LevGun LevDevice;
var LevObject LevTarget;
var bool bMovingObject, doubletapthrow;
var float AttachmentLocation; //:TODO: implement this, guy...could be very useful for moving spring loc around...

var vector vX, vY, vZ;

//note when player rotator changes (so its not >> every tick)
var rotator lastRotation;

var bool bAcceptingInput; //if the objects are ready to respond to user input
                          //   note: this implies that target has LevObject ready to be manipulated
var bool bInUse;

var bool u, d, l, r, f, b; //keypress snapshot (pressed or not)
//var vector keyVector;  //directional vector based on keypresses.
const moveAmount = 10;

//bools for doubletap push/pull
var bool dtPush, dtPull;

//constants for mana handling
const levHeldManaTickAmount = 1;
const manaTickDelay = 0.2;
const levThrowManaAmount = 10;
var float levManaTickCounter;

var bool debugShiftBool;



struct DirAxis{
    var bool bActive;
    var bool direction; //true = pos, false = neg
};
var DirAxis UpDown, RightLeft, FrontBack;

function Tick(float dt){
    if( MPC.Mana < levHeldManaTickAmount && MPC.isTargeting){
        InitTakedown();
    }


    if (doubleTapThrow && MPC.Mana >=levThrowManaAmount){
        ////////////////////////////////////////////////
        //::TODO::
        //  instead of throwing in the direction you're looking, use the mousecursor feature
        //  of finding the object you're looking at. find the vector from the levobject to the
        //  object you're looking at and throw along that axis...so you aim the throw at an
        //  object to damage it....

        if (LevTarget.Physics == PHYS_None){
            LevTarget.SetPhysics(PHYS_Karma);
            LevTarget.KWake();
        }

        LevTarget.AddImp(self.getLevToMouseVector()*100000);
        self.levThrowManaDepletion(); //take away mana on throw
        self.InitTakeDown();
        MPC.Pawn.PlaySound(Sound'WeaponSounds.BLightningGunFire');
        self.setDoubleTap(false);
       // MPC.ClientMessage("DT called in tick");
    }
    else if (LevTarget != none && LevTarget.bIsPushed && self.isInUse()){
        LevTarget.AddImp(self.getForwardVector()*100000);
        self.levThrowManaDepletion(); //take away mana on throw
        self.InitTakedown();
    }
    else if (LevTarget != none && LevTarget.bIsPulled && self.isInUse()){
        LevTarget.AddImp(self.getForwardVector()*(-100000));
        if (self.pullOnceDepletionBool == false)
            self.levThrowManaDepletion(); //take away mana on throw
        self.pullOnceDepletionBool = true;

        //self.InitTakedown();
    }
    else if (LevTarget != none && LevTarget.bIsHeld && self.isInUse()){
        self.pullOnceDepletionBool = false;
        LevDevice.GetViewAxes(vX, vY, vZ);
        LevTarget.MoveSmooth((self.P.Location + 350*vX + vect(0,0,100)) - LevTarget.Location);
        //xxMPC.ClientMessage("DID THIS WORK???????????????????");
        //self.InitTakedown();
        self.levHeldManaDepletion();
    }
    else if (LevTarget != none && LevTarget.IsLevitated() && self.isInUse()){
        //drain mana while player is levving object
        levManaTickCounter+=dt;
        if(levManaTickCounter > manaTickDelay) {
           self.levHeldManaDepletion();
           levManaTickCounter=0;
        }
        self.SetAcceptingInput(true);
        //log("now accepting input");
    }
    else if (self.AcceptingInput()){
        self.SetAcceptingInput(false);
        //log("no longer accepting input");
    }

    super.Tick(dt);
}

//################# START Constructors/Destructors ########################
// initial dummy constructor called by playercontroller's postbeginplay()
function InitUnused(){
    self.SetInUse(false);
    MPC = EnyaraPlayerController(self.Owner);
    log("SET UNUSED:"@self.Owner.name);
}

function InitSetup(LevGun LG, LevObject LO){
    log("Setting up LManager via LEVMANAGER constructor");
    log("recieved parameters: (LevGun"@LG$", LevObject"@LO$")");
    MPC = EnyaraPlayerController(self.Owner);
    P = EnyaraPawn(MPC.Pawn);
    LevDevice=LG;
    LevTarget=LO;

    if (LevTarget != none) {
      LevTarget.LManager = self;
      LevTarget.MainPlayerPawn = P;
    }
    SetInUse(true);
    MPC.isTargeting=true;

    //pass appropriate values to the LevTarget to let it know its being levved

}

//:TODO: some kind of setAttachment() setup fxn for moving the attached 'spring' around

//pseudo-destructor...no longer levving object, so LManager is no longer in use
function InitTakedown(){
    if (LevTarget != none) {
      //most objects will keep a link to this zeroed out class, EXCEPT the LevObject object
      LevTarget.LevDesynch();
    }
    //NOTE: maybe re-tool so it keeps some vars...is destroying and recreating
    //      really the most efficient way to handle this?
    //MPC.ClientMessage("TAKEDOWN CALLED");
    //MPC = none;
    P = none;
    self.LevDevice.setDType(class'Enyara.DamTypeLev');
    LevDevice = none;
    LevTarget = none;
    self.pullOnceDepletionBool = false;
    self.setdoubletap(false);
    self.restoreMovementKeys();
    SetInUse(false);
    MPC.isTargeting=false;
    //xxMPC.ClientMessage("INITTAKEDOWN CALLED! ShiftBool:"@self.debugShiftBool);

}


//testing fxn to see what happens if you call takedown without levdesynch...
function testtakedown(){
    LevTarget.SetIsLevitated(false);
}
//##################### END Constructors/Destructors ###################

//###################### START Mana Handler Fxns #########################
function levHeldManaDepletion(){
    MPC.useMana(levHeldManaTickAmount);
}

function levThrowManaDepletion(){
    MPC.useMana(levThrowManaAmount);
}
//######################## END Mana Handler Fxns #########################

//##################### START inter-class communicators ##################
function printscreen(coerce string s){
    //xxif (Self.MPC != none) MPC.ClientMessage(s);
    //xxelse log ("warning...printscreen called with no MPC set in LevManager");
}

////////////////////these are the bools used to throw/pull lobject while it is leving...
////////////////////the push/pull (while not leving) are handled based on the damage type.
//note: this fxn and calls to it should be changed to 'setDoubleTapThrow'
function setDoubleTap(bool b) { doubletapthrow = b; }

//function setDoubleTapPush(bool b) { dtPush = b; }
function setDoubleTapPullWhileLev(bool b) { dtPull = b; }



function bool RotationChange(){
    if (lastRotation != self.MPC.Rotation){
        lastRotation = self.MPC.Rotation;
        return true;
    }
    else return false;
}

//bind keys to nothing
function ignoreMovementKeys(){
    MPC.ConsoleCommand("set input w ''");
    MPC.ConsoleCommand("set input a ''");
    MPC.ConsoleCommand("set input s ''");
    MPC.ConsoleCommand("set input d ''");
    MPC.ConsoleCommand("set input Shift ''");
    MPC.ConsoleCommand("set input MouseWheelDown ''");
    MPC.ConsoleCommand("set input MouseWheelUp ''");
    log("keys ignored");
}

//restore keys to proper movement
 function restoreMovementKeys(){
    MPC.ConsoleCommand("set input w MoveForward");
    MPC.ConsoleCommand("set input a StrafeLeft");
    MPC.ConsoleCommand("set input s MoveBackward");
    MPC.ConsoleCommand("set input d StrafeRight");
    MPC.ConsoleCommand("set input Shift Duck");
    MPC.ConsoleCommand("set input MouseWheelDown NextWeapon");
    MPC.ConsoleCommand("set input MouseWheelUp PrevWeapon");
    log("keys restored");
    //MPC.ClientMessage("KEYS RESTORED");
}

//get "forward" vector for throwing the object
function vector getForwardVector(){
    local vector tmpvector;
    local rotator pRot;

    pRot = MPC.Pawn.Rotation;
    //pRot = rotator(MPC.HitLocation - LevTarget.Location);
    tmpvector = vect(1,0,0);
    return tmpvector >> pRot;
}

//get vector from levobject to mouseposition
function vector getLevToMouseVector(){
    local vector tmpvector;
    local rotator pRot;

    //pRot = MPC.Pawn.Rotation;
    pRot = rotator(MPC.HitLocation - LevTarget.Location);
    tmpvector = vect(1,0,0);
    return tmpvector >> pRot;
}

function moveSpringAttachLocation(bool u, bool d, bool r, bool l, bool f, bool b){
// - get keypress vector (directional)
// - get amount to move in each direction
// - get current spring attach location
// - add the amount-to-move vector to current spring attach vector
// - call setSpringAttachLocation in LevTarget

     local vector iLoc, fLoc , Distance, kVector, tmpvector;
     local rotator pRot;
     local float x, y, z;

     pRot = MPC.Pawn.Rotation;

     tmpvector = getKeyVector(u, d, r, l, f, b);

     if (tmpvector != vect(0,0,0)){

            pRot = MPC.Pawn.Rotation;
            kVector = tmpvector >> pRot;

        Distance = kVector * moveAmount;
        //kVector = kVector * vector(prot);
        // kVector = tmpvector * vector(prot);

        // tmpVector = (vector(prot));
        //tmpVector.Z = 1;
        //Distance = (tmpVector * moveAmount);
        //kVector = kVector * Distance;

        iLoc = LevTarget.getSpringAttachLocation();
        //Distance =( moveAmount * kVector);
        fLoc = (iLoc + Distance); //alter spring's current location by Distance vector

        //printScreen(KVector@"      "@Distance);
        LevTarget.setSpringAttachLocation( fLoc );

    }

  //  LevTarget.setSpringAttachLocation( fLoc );
}

function vector getKeyVector( bool u, bool d, bool r, bool l, bool f, bool b ){
    local vector keyVector;
    keyVector = vect(0,0,0); //zero out, just to be safe

    if (u || d){
        //u gets priority over d
        if (u) keyVector.Z = 1;
        else keyVector.Z = -1;
    }

    if (r || l){
        //r gets priority over l
        if (r) keyVector.Y = 1;
        else keyVector.Y = -1;
    }

    if (f || b){
        //f gets priority over b
        if (f) keyVector.X = 1;
        else keyVector.X = -1;
    }

    return keyVector;
}
//##################### END inter-class communicators ####################



//####################### START class lock/unlock fxns ###################
function SetInUse(bool b){
    if (b) bInUse = true;  //manager is managing
    else bInUse = false;   //manager is not managing
}

function bool isInUse(){
    return self.bInUse;
}
//####################### END class lock/unlock fxns #####################

//###################### START debug/helper fxns #########################
function logAttributes(){
    log("########### current attributes for"@self.Name@"############");
    log("# MPC:      "@MPC.name);
    log("# P:        "@P.name);
    log("# LevDevice:"@LevDevice.Name);
    log("# LevTarget:"@LevTarget.Name);
    log("# bInUse:   "@bInUse);
    log("############");
}

function SetAcceptingInput(bool b){
    if (b) bAcceptingInput = true;
    else bAcceptingInput = false;
}

function bool AcceptingInput(){
    return self.bAcceptingInput;
}

function float getLevelSeconds(){
    return Level.TimeSeconds;
}
//######################## END debug/helper fxns #########################


defaultproperties {

}
